package cn.iocoder.yudao.module.written.exam.dal.redis.llm;

import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import cn.iocoder.yudao.module.written.exam.dal.dataobject.llm.LlmConversationDO;
import cn.iocoder.yudao.module.written.exam.dal.dataobject.llm.LlmFileDO;
import cn.iocoder.yudao.module.written.exam.dal.dataobject.llm.LlmMessageDO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Repository;

import javax.annotation.Resource;
import java.time.Duration;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

/**
 * 大模型聊天 Redis DAO
 *
 * @author 芋道源码
 */
@Repository
@Slf4j
public class LlmChatRedisDAO {

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    /**
     * Redis Key 前缀
     */
    private static final String REDIS_KEY_PREFIX = "llm:chat:";

    /**
     * 会话Key前缀
     */
    private static final String CONVERSATION_KEY_PREFIX = REDIS_KEY_PREFIX + "conversation:";

    /**
     * 消息Key前缀
     */
    private static final String MESSAGE_KEY_PREFIX = REDIS_KEY_PREFIX + "message:";

    /**
     * 文件Key前缀
     */
    private static final String FILE_KEY_PREFIX = REDIS_KEY_PREFIX + "file:";

    /**
     * 用户会话列表Key前缀
     */
    private static final String USER_CONVERSATIONS_KEY_PREFIX = REDIS_KEY_PREFIX + "user:conversations:";

    /**
     * 会话消息列表Key前缀
     */
    private static final String CONVERSATION_MESSAGES_KEY_PREFIX = REDIS_KEY_PREFIX + "conversation:messages:";

    /**
     * 过期时间：7天
     */
    private static final Duration EXPIRE_TIME = Duration.ofDays(7);

    // ==================== 会话管理 ====================

    /**
     * 生成会话ID
     */
    public String generateConversationId() {
        return UUID.randomUUID().toString();
    }

    /**
     * 保存会话
     */
    public void saveConversation(LlmConversationDO conversation) {
        String key = buildConversationKey(conversation.getId());
        stringRedisTemplate.opsForValue().set(key, JSONUtil.toJsonStr(conversation), EXPIRE_TIME);
        
        // 添加到用户会话列表
        String userKey = buildUserConversationsKey(conversation.getUserId());
        stringRedisTemplate.opsForList().leftPush(userKey, conversation.getId());
        stringRedisTemplate.expire(userKey, EXPIRE_TIME);
    }

    /**
     * 根据ID查询会话
     */
    public LlmConversationDO selectConversationById(String conversationId) {
        String key = buildConversationKey(conversationId);
        String value = stringRedisTemplate.opsForValue().get(key);
        return StrUtil.isNotBlank(value) ? JSONUtil.toBean(value, LlmConversationDO.class) : null;
    }

    /**
     * 更新会话
     */
    public void updateConversation(LlmConversationDO conversation) {
        saveConversation(conversation);
    }

    /**
     * 查询用户会话列表
     */
    public List<LlmConversationDO> selectUserConversations(String userId) {
        String userKey = buildUserConversationsKey(userId);
        List<String> conversationIds = stringRedisTemplate.opsForList().range(userKey, 0, -1);
        
        List<LlmConversationDO> conversations = new ArrayList<>();
        if (conversationIds != null) {
            for (String conversationId : conversationIds) {
                LlmConversationDO conversation = selectConversationById(conversationId);
                if (conversation != null) {
                    conversations.add(conversation);
                }
            }
        }
        return conversations;
    }

    // ==================== 消息管理 ====================

    /**
     * 生成消息ID
     */
    public String generateMessageId() {
        return UUID.randomUUID().toString();
    }

    /**
     * 保存消息
     */
    public void saveMessage(LlmMessageDO message) {
        String key = buildMessageKey(message.getId());
        stringRedisTemplate.opsForValue().set(key, JSONUtil.toJsonStr(message), EXPIRE_TIME);
        
        // 添加到会话消息列表
        String conversationKey = buildConversationMessagesKey(message.getConversationId());
        stringRedisTemplate.opsForList().rightPush(conversationKey, message.getId());
        stringRedisTemplate.expire(conversationKey, EXPIRE_TIME);
    }

    /**
     * 根据ID查询消息
     */
    public LlmMessageDO selectMessageById(String messageId) {
        String key = buildMessageKey(messageId);
        String value = stringRedisTemplate.opsForValue().get(key);
        return StrUtil.isNotBlank(value) ? JSONUtil.toBean(value, LlmMessageDO.class) : null;
    }

    /**
     * 更新消息
     */
    public void updateMessage(LlmMessageDO message) {
        saveMessage(message);
    }

    /**
     * 查询会话消息列表
     */
    public List<LlmMessageDO> selectConversationMessages(String conversationId) {
        String conversationKey = buildConversationMessagesKey(conversationId);
        List<String> messageIds = stringRedisTemplate.opsForList().range(conversationKey, 0, -1);
        
        List<LlmMessageDO> messages = new ArrayList<>();
        if (messageIds != null) {
            for (String messageId : messageIds) {
                LlmMessageDO message = selectMessageById(messageId);
                if (message != null) {
                    messages.add(message);
                }
            }
        }
        return messages;
    }

    // ==================== 文件管理 ====================

    /**
     * 生成文件ID
     */
    public String generateFileId() {
        return UUID.randomUUID().toString();
    }

    /**
     * 保存文件信息
     */
    public void saveFile(LlmFileDO file) {
        String key = buildFileKey(file.getId());
        stringRedisTemplate.opsForValue().set(key, JSONUtil.toJsonStr(file), EXPIRE_TIME);
    }

    /**
     * 根据ID查询文件
     */
    public LlmFileDO selectFileById(String fileId) {
        String key = buildFileKey(fileId);
        String value = stringRedisTemplate.opsForValue().get(key);
        return StrUtil.isNotBlank(value) ? JSONUtil.toBean(value, LlmFileDO.class) : null;
    }

    /**
     * 更新文件信息
     */
    public void updateFile(LlmFileDO file) {
        saveFile(file);
    }

    // ==================== 私有方法 ====================

    /**
     * 构建会话Key
     */
    private String buildConversationKey(String conversationId) {
        return CONVERSATION_KEY_PREFIX + conversationId;
    }

    /**
     * 构建消息Key
     */
    private String buildMessageKey(String messageId) {
        return MESSAGE_KEY_PREFIX + messageId;
    }

    /**
     * 构建文件Key
     */
    private String buildFileKey(String fileId) {
        return FILE_KEY_PREFIX + fileId;
    }

    /**
     * 构建用户会话列表Key
     */
    private String buildUserConversationsKey(String userId) {
        return USER_CONVERSATIONS_KEY_PREFIX + userId;
    }

    /**
     * 构建会话消息列表Key
     */
    private String buildConversationMessagesKey(String conversationId) {
        return CONVERSATION_MESSAGES_KEY_PREFIX + conversationId;
    }

} 